package co.dianjiu.aio.server;

import co.dianjiu.aio.util.InputUtils;

import java.io.IOException;
import java.io.PrintStream;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousServerSocketChannel;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;
import java.util.Scanner;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

/**
 * @author DianJiu
 * @website https://dianjiu.co
 * @email dianjiu@dianjiu.cc
 * @date 2021/8/2 17:37
 * @desc TODO
 */
public class AIOServerHandler {
    private AsynchronousServerSocketChannel server;
    private Scanner scanner;
    private PrintStream out;
    private boolean flag = true;

    public AIOServerHandler(AsynchronousServerSocketChannel server) {
        this.server = server;
    }

    //
    public void startWithFuture() throws InterruptedException,
            ExecutionException, TimeoutException {
        while (true) {// 循环接收客户端请求
            Future<AsynchronousSocketChannel> future = server.accept();
            AsynchronousSocketChannel socket = future.get();// get() 是为了确保 accept 到一个连接
            handleWithFuture(socket);
        }
    }
    public void handleWithFuture(AsynchronousSocketChannel channel) throws InterruptedException, ExecutionException, TimeoutException {
        ByteBuffer readBuf = ByteBuffer.allocate(1024);
        readBuf.clear();
        // 一次可能读不完
        while (true) {
            //get 是为了确保 read 完成，超时时间可以有效避免DOS攻击，如果客户端一直不发送数据，则进行超时处理
            Integer integer = channel.read(readBuf).get(10, TimeUnit.SECONDS);
            //打印获得的字节数
            System.out.println("readSize:" + integer);
            if (integer == -1) {
                break;
            }
            readBuf.flip();
            //获取读取的数据
            String body = new String(readBuf.array()).trim();
            System.out.println("收到客户端发来消息：\n" + body);
            readBuf.clear();
            //获取控制台输入流
            Scanner scan = new Scanner(System.in);
            scan.useDelimiter("\n");
            String replyData = InputUtils.getString("请输入要回复的内容：").trim();
            ByteBuffer buffer = ByteBuffer.allocate(1024);
            buffer.put(replyData.getBytes());
            buffer.flip();
            channel.write(buffer).get();
        }
    }

    public void startWithCompletionHandler() throws InterruptedException,
            ExecutionException, TimeoutException {
        server.accept(null,
                new CompletionHandler<AsynchronousSocketChannel, Object>() {
                    public void completed(AsynchronousSocketChannel result, Object attachment) {
                        // 再此接收客户端连接
                        server.accept(attachment, this);
                        handleWithCompletionHandler(result);
                    }

                    @Override
                    public void failed(Throwable exc, Object attachment) {
                        exc.printStackTrace();
                    }
                });
    }

    public void handleWithCompletionHandler(final AsynchronousSocketChannel channel) {
        try {
            readWithCompletionHandler(channel);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void readWithCompletionHandler(AsynchronousSocketChannel asc) {
        //创建缓冲区
        final ByteBuffer buffer = ByteBuffer.allocate(1024);
        asc.read(buffer,10L, TimeUnit.SECONDS, null,  new CompletionHandler<Integer, Object>() {
            @Override
            public void completed(Integer result, Object attachment) {
                //打印获得的字节数
                System.out.println("readSize:" + result);
                if (result == -1) {
                    try {
                        asc.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                    return;
                }
                //进行读取之前重新设置pos和limit
                buffer.flip();
                //获取读取的数据
                String body = new String(buffer.array()).trim();
                System.out.println("收到客户端发来消息：\n" + body);
                asc.read(buffer, 10L, TimeUnit.SECONDS, null, this);
                buffer.clear();
                //获取控制台输入流
                Scanner scan = new Scanner(System.in);
                scan.useDelimiter("\n");
                String replyData = InputUtils.getString("请输入要回复的内容：").trim();
                // 写回消息
                writeWithCompletionHandler(asc,replyData);
            }

            @Override
            public void failed(Throwable exc, Object attachment) {
                exc.printStackTrace();
            }
        });
    }

    private void writeWithCompletionHandler(AsynchronousSocketChannel asc, String resp) {
        try {
            ByteBuffer buffer = ByteBuffer.allocate(1024);
            buffer.put(resp.getBytes());
            buffer.flip();
            //get写不写都行
            asc.write(buffer).get();
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}
